using System;
using System.Collections;
using System.Diagnostics.Contracts;
using System.Reflection;

namespace Charisma.Metadata
{
    public sealed class MetaField
    {
        public readonly Func<object, IList, IEnumerable> CollectionInitializer;
        public readonly MemberInfo Field;
        public readonly Func<object, object> GetValue;
        public readonly string Name;
        public readonly MetaType Owner;
        public readonly Action<object, object> SetValue;
        public readonly Type ValueType;
        private readonly string alias;


        internal MetaField(MetaType owner, MetaFieldDescription description)
            : this(owner, description.Name,
                   ReflectionService.MakeGetter(owner.Type, description.Field),
                   description.Field is PropertyInfo && ((PropertyInfo) description.Field).CanWrite ||
                   description.Field is FieldInfo && !((FieldInfo) description.Field).IsInitOnly
                       ? ReflectionService.MakeSetter(owner.Type, description.Field)
                       : delegate { })
        {
            Contract.Requires(owner != null);
            Contract.Requires(owner.Type != null);

            Field = description.Field;
            alias = description.Alias;
            CollectionInitializer = description.CollectionInitializer;
            ValueType = Field.GetMemberType();
        }

        internal MetaField(MetaType owner, string name, Func<Object, Object> getter, Action<Object, Object> setter)
        {
            Contract.Requires(owner != null);
            Contract.Requires(!String.IsNullOrEmpty(name));
            Contract.Requires(getter != null);

            Owner = owner;
            Name = name;
            GetValue = getter;
            SetValue = setter;
            ValueType = typeof (object);
        }

        public string Alias
        {
            get { return alias ?? Name; }
        }

        public override string ToString()
        {
            Type valueType = Field is PropertyInfo
                                 ? ((PropertyInfo) Field).PropertyType
                                 : ((FieldInfo) Field).FieldType;
            return string.Format("{0} {1}", valueType, Name);
        }
    }
}